﻿#include "Path.h"

SPath::SPath()
{

}


SPath::SPath(const CString& InPath)
:LowLevel(InPath.GetData())
{

}


SPath::SPath(const char32_t * InPath)
:LowLevel(InPath)
{

}

SPath::SPath(const char * InPath)
:LowLevel(InPath)
{

}

SPath::SPath(const std::filesystem::path& InPath)
:LowLevel(InPath)
{

}

CString SPath::ToString() const
{
    return LowLevel.u32string().c_str();
}

void SPath::FromString(const CString& InStringExpression)
{
    LowLevel=std::filesystem::path (InStringExpression.GetData());
}


SPath SPath::Parent() const
{
    return LowLevel.parent_path();
}

void SPath::Append(const SPath & WillBeAppendded) 
{
    LowLevel/=WillBeAppendded.LowLevel;
}

void SPath::Append(const CString &WillBeAppendded) 
{
    LowLevel/=WillBeAppendded.GetData();
}

SPath SPath::Combine(const SPath &Left, const SPath &Right)
{
    return Left.LowLevel/Right.LowLevel;
}

void SPath::operator/=(const SPath &WillBeAppendded)
{
    LowLevel/=WillBeAppendded.LowLevel;
}

SPath SPath::operator / (const SPath& WillBeAppendded) const
{
    return LowLevel/WillBeAppendded.LowLevel; 
}

bool SPath::operator == (const SPath& Right) const
{
    return LowLevel==Right.LowLevel; 
}

bool SPath::IsSameWith(const SPath &Other) const
{
    if(IsEmpty()!=Other.IsEmpty())
    {
        return false;
    }

    return std::filesystem::equivalent(LowLevel,Other.LowLevel);
}

bool SPath::IsEmpty() const
{
    return LowLevel.empty();
}

CString SPath::IsValidFileOrFolderName(const CString &InName)
{
    if(InName.IsEmpty())
    {
        return U"文件名不能为空";
    }

    if(InName.GetLength()> 255)
    {
        return U"文件名过长";
    }

    if(InName.ContainsAnyOf(U"\\/:*?\"<>|"))
    {
        return U"文件名包含非法字符";
    }

    if(InName.EndsWith(U".") || InName.EndsWith(U" "))
    {
        return U"文件名不能以.或空格结尾";
        
    }

    if(InName.StartsWith(U" "))
    {
        return U"文件名不能空格开头";
    }

    const static TVector<CString> InvalidNames=
    {
        U".",
        U"..",
        U"CON",
        U"PRN",
        U"AUX",
        U"NUL",
        U"COM1",
        U"COM2",
        U"COM3",
        U"COM4",
        U"COM5",
        U"COM6",
        U"COM7",
        U"COM8",
        U"COM9",
        U"LPT1",
        U"LPT2",
        U"LPT3",
        U"LPT4",
        U"LPT5",
        U"LPT6",
        U"LPT7",
        U"LPT8",
        U"LPT9",
    };
    
    for(auto& InvalidName:InvalidNames)
    {
        if(InName==InvalidName)
        {
            return U"文件名不能为"+InvalidName;
        }
    }

    return U"";
}

CString SPath::HasValidFileOrFolderName() const
{
    CString FileName=GetFileOrDirectoryName();

    return IsValidFileOrFolderName(FileName);
}

bool SPath::Exists() const
{
    return std::filesystem::exists(LowLevel);
}

bool SPath::Delete() const
{
    return std::filesystem::remove(LowLevel);
}

SPath SPath::GetRelativeTo(const SPath & Base) const
{
    return LowLevel.lexically_relative(Base.LowLevel);
}

bool SPath::IsInside(const SPath &InFolder) const
{
    auto A=LowLevel.lexically_normal();
    auto B=InFolder.LowLevel.lexically_normal();

    if(A==B)
    {
        return false;
    }

    return A.native().find(B.native())==0;
}

SPath SPath::ToAbsolute() const
{
    return LowLevel.lexically_normal();
}

std::filesystem::path SPath::GetLowLevel() const
{
    return LowLevel;
}

bool SPath::IsDirectory() const
{
    return std::filesystem::is_directory(LowLevel);
}

bool SPath::IsFile() const
{
    return std::filesystem::is_regular_file(LowLevel);
}

bool SPath::IsEmptyDirectory() const
{
    if(!IsDirectory())
    {
        return false;
    }

    for(auto& p: std::filesystem::directory_iterator(LowLevel))
    {
        return false;
    }
    return  true;
}
 
TVector<SPath> SPath::ListFiles() const 
{
    TVector<SPath> Result;

    if(IsDirectory())
    {
        for(auto& p: std::filesystem::directory_iterator(LowLevel))
        {
            if(p.is_directory())
            {
                continue;
            }

            Result.Add(SPath(p.path()));
        }
    }

    return Result;
}

TVector<SPath> SPath::ListSubDirectories() const
{
    TVector<SPath> Result;

    if(IsDirectory())
    {
        for(auto& p: std::filesystem::directory_iterator(LowLevel))
        {
            if(!p.is_directory())
            {
                continue;
            }

            Result.Add(SPath(p.path()));
        }
    }

    return Result;
}

CString SPath::GetFileOrDirectoryName() const
{
    return LowLevel.filename().u32string().c_str();
}

bool SPath::IsFileWithExtension(const CString &Extension, bool IgnoreCase) const
{
    if(!LowLevel.has_filename())
    {
        return false;
    }

    auto PathExtension=GetExtension();

    if(!PathExtension.HasValue())
    {
        return false;
    }

    if(IgnoreCase)
    {
        return PathExtension.GetValue().ToLower()==Extension.ToLower();
    }

    return PathExtension.GetValue()==Extension;
}

bool SPath::IsAssetFile() const
{
    return IsFileWithExtension(U".asset");
}

SPath SPath::RemoveFinalExtension() const
{
    return SPath(LowLevel.stem());
}

CString SPath::GetBaseFileName() const
{
    return CString(LowLevel.stem().u32string().c_str());
}

void SPath::SetExtension(const CString& Extension)
{
    LowLevel.replace_extension(Extension.GetData());
}

TOptional<CString> SPath::GetExtension() const
{
    if(!LowLevel.has_extension())
    {
        return TOptional<CString>();
    }

    return CString(LowLevel.extension().u32string().c_str());
}